import 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter_syt/starter/platform/channel_error.dart';

import '../app_context.dart';
import '../processor.dart';

typedef OnNativeCall = void Function(String args);

typedef OnNativeCallError = Future? Function(int codeCode, String errorMsg);

class NativeNavProcessor with Processor<dynamic> {
  @override
  Future<void> postProcessor(AppContext appContext, [dynamic param]) {
    appContext.channelApi = FlutterChannelApi.create();
    return Future.value();
  }
}

mixin ChannelApi {
  Future<dynamic> call(String apiName, String? args);

  void listen(String apiName, OnNativeCall caller);
}

class FlutterChannelApi with ChannelApi {
  MethodChannel _channel = MethodChannel("com.app.framework.channel/api");
  Map<String, OnNativeCall> _map = {};

  FlutterChannelApi._() {
    /**
     * 原生调用结构如下：
     * {
     *  "status": true / false    // 成功 / 失败
     *  "content": {              // 仅在 status 为 true 有该字段，该字段可空
     *     "bizKey": "bizValue",
     *     "bizKey": "bizValue",
     *  },
     *  errorCode:                // 仅在 status 为 false 有该字段
     *  errorMsg:                 // 仅在 status 为 false 有该字段
     * }
     */
    _channel.setMethodCallHandler((call) async {
      debugPrint(
          "Native Call, method-> ${call.method}, arguments-> ${call.arguments}");
      if (!_map.containsKey(call.method)) {
        throw ChannelException.createUnImplementationException();
      }
      var func = _map[call.method];
      if (func != null) {
        func(call.arguments);
      }
    });
  }

  factory FlutterChannelApi.create() {
    var api = FlutterChannelApi._();

    return api;
  }

  @override
  Future<dynamic> call(String apiName, String? args) async {
    return await _channel.invokeMethod(apiName, args ?? "");
  }

  @override
  void listen(String apiName, OnNativeCall caller) async {
    if (_map.containsKey(apiName)) {
      debugPrint('[$apiName] already registered');
      return;
    }
    _map[apiName] = caller;
  }
}
